// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable StringLiteralTypo
// ReSharper disable UnusedParameter.Local

/*
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using System;

#endregion\

#nullable enable

namespace AM.Reporting.Barcode.QRCode
{
/*  /// <summary> JAVAPORT: This should be combined with BitArray in the future, although that class is not yet
  /// dynamically resizeable. This implementation is reasonable but there is a lot of function calling
  /// in loops I'd like to get rid of.
  ///
  /// </summary>
  /// <author>  satorux@google.com (Satoru Takabayashi) - creator
  /// </author>
  /// <author>  dswitkin@google.com (Daniel Switkin) - ported from C++
  /// </author>
  /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
  /// </author>*/
    internal sealed class BitVector
    {
        public sbyte[] Array { get; private set; }

        private int sizeInBits;

        // For efficiency, start out with some room to work.
        private const int DEFAULT_SIZE_IN_BYTES = 32;

        public BitVector()
        {
            sizeInBits = 0;
            Array = new sbyte[DEFAULT_SIZE_IN_BYTES];
        }

        // Return the bit value at "index".
        public int at (int index)
        {
            if (index < 0 || index >= sizeInBits)
            {
                throw new ArgumentException ("Bad index: " + index);
            }

            var value_Renamed = Array[index >> 3] & 0xff;
            return (value_Renamed >> (7 - (index & 0x7))) & 1;
        }

        // Return the number of bits in the bit vector.
        public int size()
        {
            return sizeInBits;
        }

        // Return the number of bytes in the bit vector.
        public int sizeInBytes()
        {
            return (sizeInBits + 7) >> 3;
        }

        // Append one bit to the bit vector.
        public void appendBit (int bit)
        {
            if (!(bit is 0 or 1))
            {
                throw new ArgumentException ("Bad bit");
            }

            unchecked
            {
                var numBitsInLastByte = sizeInBits & 0x7;

                // We'll expand array if we don't have bits in the last byte.
                if (numBitsInLastByte == 0)
                {
                    appendByte (0);
                    sizeInBits -= 8;
                }

                // Modify the last byte.
                Array[sizeInBits >> 3] |= (sbyte)((bit << (7 - numBitsInLastByte)));
                ++sizeInBits;
            }
        }

        // Append "numBits" bits in "value" to the bit vector.
        // REQUIRES: 0<= numBits <= 32.
        //
        // Examples:
        // - appendBits(0x00, 1) adds 0.
        // - appendBits(0x00, 4) adds 0000.
        // - appendBits(0xff, 8) adds 11111111.
        public void appendBits (int value_Renamed, int numBits)
        {
            if (numBits is < 0 or > 32)
            {
                throw new ArgumentException ("Num bits must be between 0 and 32");
            }

            var numBitsLeft = numBits;
            while (numBitsLeft > 0)
            {
                // Optimization for byte-oriented appending.
                if ((sizeInBits & 0x7) == 0 && numBitsLeft >= 8)
                {
                    var newByte = (value_Renamed >> (numBitsLeft - 8)) & 0xff;
                    appendByte (newByte);
                    numBitsLeft -= 8;
                }
                else
                {
                    var bit = (value_Renamed >> (numBitsLeft - 1)) & 1;
                    appendBit (bit);
                    --numBitsLeft;
                }
            }
        }

        // Append "bits".
        public void appendBitVector (BitVector bits)
        {
            var size = bits.size();
            for (var i = 0; i < size; ++i)
            {
                appendBit (bits.at (i));
            }
        }

        // Modify the bit vector by XOR'ing with "other"
        public void xor (BitVector other)
        {
            if (sizeInBits != other.size())
            {
                throw new ArgumentException ("BitVector sizes don't match");
            }

            var sizeInBytes = (sizeInBits + 7) >> 3;
            for (var i = 0; i < sizeInBytes; ++i)
            {
                // The last byte could be incomplete (i.e. not have 8 bits in
                // it) but there is no problem since 0 XOR 0 == 0.
                Array[i] ^= other.Array[i];
            }
        }

        // Add a new byte to the end, possibly reallocating and doubling the size of the array if we've
        // run out of room.
        private void appendByte (int value_Renamed)
        {
            unchecked
            {
                if ((sizeInBits >> 3) == Array.Length)
                {
                    var newArray = new sbyte[(Array.Length << 1)];

                    // Redivivus.in Java to c# Porting update
                    // 30/01/2010
                    // added namespace system
                    System.Array.Copy (Array, 0, newArray, 0, Array.Length);
                    Array = newArray;
                }

                Array[sizeInBits >> 3] = (sbyte)value_Renamed;
                sizeInBits += 8;
            }
        }
    }
}
